package auth

import (
	"context"
	"errors"
	"fmt"

	"github.com/golang-jwt/jwt/v5"
)

const claimID = "id"

type service struct {
	secret []byte
}

func NewService(secret string) (*service, error) {
	if secret == "" {
		return nil, errors.New("secret must not be empty")
	}
	return &service{
		secret: []byte(secret),
	}, nil
}

func (s *service) IssueToken(ctx context.Context, userId string) (string, error) {
	token := jwt.NewWithClaims(jwt.SigningMethodHS256,
		jwt.MapClaims{
			claimID: userId,
		})

	sign, err := token.SignedString(s.secret)
	if err != nil {
		return "", fmt.Errorf("failed to sign the JWT: %w", err)
	}

	return sign, nil
}

func (s *service) ValidateToken(ctx context.Context, token string) (string, error) {
	// parse & verfy the token
	decodeToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
		if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
		}

		return s.secret, nil
	})
	if err != nil {
		return "", fmt.Errorf("invalid token: %w", err)
	}
	// extract the claim
	claims, ok := decodeToken.Claims.(jwt.MapClaims)
	if !decodeToken.Valid || !ok {
		return "", errors.New("faield to extract claims")
	}

	id, ok := claims[claimID].(string)
	if !ok {
		return "", errors.New("faield to extract User ID from claims")
	}

	return id, nil
}
